﻿/*********************
 * 特征提取及分析
 * 魏继琼
 * 2011年10月7日15:45:27
 * ********************/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections.Specialized;
using VideoFlowStatistics.EntityClass;

namespace VideoFlowStatistics.Class
{
    class FeatureAnalysis
    {
        float[,] motionGrid;
        /// <summary>
        /// 现有画面运动
        /// </summary>
        public float[,] MotionGrid
        {
            get { return motionGrid; }
            set { motionGrid = value; }
        }

        /// 区域结合
        /// </summary>
        public Dictionary<string, IList<Cxy>> profileArea
        {
            get;
            set;
        }

        float MotionAmount = Properties.Settings.Default.MotionAmount;

        List<Cxy> Line1 = new List<Cxy>();
        List<Cxy> Line2 = new List<Cxy>();
        List<Cxy> Line3 = new List<Cxy>();

        private List<Cxy> diffArea;

        public FeatureAnalysis()
        {
            InitLine();
        }

        //获取两条线的坐标并写入Line1，Line2的变量
        private void InitLine()
        {
            StringCollection line1 = Properties.Settings.Default.Line1;
            StringCollection line2 = Properties.Settings.Default.Line2;
            for (int i = 0; i < line1.Count; i++)
            {
                string[] oneLine = line1[i].Split(';');

                Line1.Add(new Cxy() { X = Convert.ToInt32(oneLine[0]), Y = Convert.ToInt32(oneLine[1]) });

            }

            for (int i = 0; i < line2.Count; i++)
            {
                string[] oneLine = line2[i].Split(';');

                Line2.Add(new Cxy() { X = Convert.ToInt32(oneLine[0]), Y = Convert.ToInt32(oneLine[1]) });
            }
        }

        /// <summary>
        /// 判断是否撞击Line1
        /// </summary>
        /// <returns></returns>
        public bool IsRunInLine1()
        {
            return IsRunInLine(Line1);
        }

        /// <summary>
        /// 判断是否撞击Line2
        /// </summary>
        /// <returns></returns>
        public bool IsRunInLine2()
        {
            return IsRunInLine(Line2);
        }

        /// <summary>
        /// 判断是否撞击Line3
        /// </summary>
        /// <returns></returns>
        public bool IsRunInLine3()
        {
            return IsRunInLine(Line3);
        }

        private bool IsRunInLine(IList<Cxy> li)
        {
            for (int i = 0; i < li.Count; i++)
            {
                //if (motionGrid[li[i].X, li[i].Y] >= MotionAmount)修改XY坐标
                if (motionGrid[li[i].Y, li[i].X] >= MotionAmount)
                {
                    return true;
                }
            }

            return false;
        }

        /// <summary>
        /// 判断是否撞击Line1
        /// </summary>
        /// <returns></returns>
        public bool IsRunInLine1(IList<Cxy> area)
        {
            return IsRunInLine(Line1, area);
        }

        /// <summary>
        /// 判断是否撞击Line2
        /// </summary>
        /// <returns></returns>
        public bool IsRunInLine2(IList<Cxy> area)
        {
            return IsRunInLine(Line2, area);
        }

        private bool IsRunInLine(IList<Cxy> li, IList<Cxy> area)
        {
            for (int i = 0; i < li.Count; i++)
            {
                var tempArea = area.Where(m => (m.X == li[i].X && m.Y == li[i].Y));
                if (tempArea.Count() > 0)
                {
                    if (motionGrid[li[i].Y, li[i].X] >= MotionAmount)
                    {
                        return true;
                    }
                }
            }
            return false;
        }

        /// <summary>
        /// 获取区域
        /// 存储在Profile 类集合中
        /// </summary>
        /// <param name="buf">红色区字节数组</param>
        /// <param name="width">图片宽像素</param>
        public void FindArea()
        {
            diffArea = new List<Cxy>();
            profileArea = new Dictionary<string, IList<Cxy>>();

            for (int j = 0; j < motionGrid.GetLength(1); j++)
            {
                for (int i = 0; i < motionGrid.GetLength(0); i++)
                {
                    //if (motionGrid[i, j] < MotionAmount)//检查是否忽略其运动等级
                    if (motionGrid[j, i] < MotionAmount)//检查是否忽略其运动等级
                    {
                        continue;
                    }
                    if (diffArea.Where(m => m.X == i && m.Y == j).Count() > 0)//检查该点已经被使用
                    {
                        continue;
                    }

                    List<Cxy> arr = new List<Cxy>();
                    Cxy index = new Cxy() { X = i, Y = j };
                    FindProfile(index, arr);
                    if (arr.Count > 1)//如果小于某一面积则忽略
                    {
                        string key = Guid.NewGuid().ToString();
                        profileArea.Add(key, arr);
                    }
                }
            }
        }

        /// <summary>
        /// 递归判断有多少闭合区域
        /// </summary>
        /// <param name="index">当前点</param>
        /// <param name="arr"></param>
        private void FindProfile(Cxy index, IList<Cxy> arr)
        {
            //if (motionGrid[index.X, index.Y] < MotionAmount)//检查是否忽略其运动等级
            if (motionGrid[index.Y, index.X] < MotionAmount)//检查是否忽略其运动等级
            {
                return;
            }
            var temp = diffArea.Where(m => (m.X == index.X && m.Y == index.Y));
            if (temp.Count() > 0)//检查该点已经被使用
            {
                return;
            }

            arr.Add(index);
            diffArea.Add(index);

            Cxy up = new Cxy() { X = index.X, Y = index.Y - 1 }; //上
            Cxy down = new Cxy() { X = index.X, Y = index.Y + 1 };//下
            Cxy left = new Cxy() { X = index.X - 1, Y = index.Y };//左
            Cxy right = new Cxy() { X = index.X + 1, Y = index.Y };//右

            if (IsCrossBorde(up))
            {
                FindProfile(up, arr);
            }
            if (IsCrossBorde(down))
            {
                FindProfile(down, arr);
            }
            if (IsCrossBorde(left))
            {
                FindProfile(left, arr);
            }
            if (IsCrossBorde(right))
            {
                FindProfile(right, arr);
            }
        }

        //判断是否越界
        private bool IsCrossBorde(Cxy index)
        {
            if (index.X >= motionGrid.GetLength(0) || index.X < 1)
            {
                return false;
            }
            if (index.Y >= motionGrid.GetLength(1) || index.Y < 1)
            {
                return false;
            }
            return true;
        }

    }
}
